package com.jiliason.testTools;

import com.google.common.collect.Lists;
import com.jiliason.testTools.constant.TCt;
import com.jiliason.testTools.entity.TestDataPojo;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Stack;
import java.util.concurrent.atomic.AtomicInteger;

public class InitTestData {

    public static volatile List<String> obsoletes = Lists.newCopyOnWriteArrayList();

    public static List<TestDataPojo> getTestDataByPath(Path path) throws IOException {
        List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
        if (lines.isEmpty()) return Lists.newArrayList();
        // 清空不能解析的行的 存储list
        obsoletes = Lists.newCopyOnWriteArrayList();
        return caseFileParsing(path, lines);
    }

    private static List<TestDataPojo> caseFileParsing(Path path, List<String> lines) {
        List<TestDataPojo> dataList = Lists.newArrayList();

        int cursor = 0;
        AtomicInteger orderBy = new AtomicInteger(1);
        // 跳commend
        while((cursor = skipCommend(cursor, lines)) < lines.size()) {
            String line = lines.get(cursor).trim();
            String tag = checkLineHeader(line);
            if (tag.equals(TCt.tagTitle)) {
                cursor = parsing(cursor, orderBy, path, dataList, lines);
            } else {
                obsoletes.add(cursor + "行:" + line);
                cursor++;
            }
        }
        return dataList;
    }

    private static int parsing(int cursor, AtomicInteger orderBy, Path path, List<TestDataPojo> dataList, List<String> lines) {
        String line = null;
        while (cursor < lines.size() && TCt.tagTitle.equals(checkLineHeader(line = lines.get(cursor).trim()))) {
            cursor = parsingTIO(cursor, orderBy, path, dataList, lines);
            // 跳commend
            cursor = skipCommend(cursor, lines);
        }
        if (cursor < lines.size()) {
            obsoletes.add(cursor + "行:" + line);
        }

        return cursor;
    }

    private static int parsingTIO(int cursor, AtomicInteger orderBy, Path path, List<TestDataPojo> dataList, List<String> lines) {
        TestDataPojo data = new TestDataPojo(lines.get(cursor).trim());
        int titleLine = cursor;
        cursor++;

        int inputLine = setInOrOut(data, cursor, lines, TCt.tagIn);
        cursor = inputLine;
        int outputLine = setInOrOut(data, cursor, lines, TCt.tagOut);
        cursor = outputLine;

        if (data.empty()) {
            obsoletes.add(titleLine + "行:" + lines.get(titleLine).trim());
            if (StringUtils.isNotEmpty(data.getInputString())) obsoletes.add(inputLine-1 + "行:" + lines.get(inputLine-1).trim());
            if (StringUtils.isNotEmpty(data.getAnswer())) obsoletes.add(outputLine-1 + "行:" + lines.get(outputLine-1).trim());
        } else {
            // 添加合规的测试数据
            addConformityData(dataList, data, path, orderBy);
        }

        return cursor;
    }

    private static void addConformityData(List<TestDataPojo> dataList, TestDataPojo data, Path path, AtomicInteger orderBy) {
        data.setFileCategory(path.getFileName().toString());
        data.setOrderBy(orderBy.get());

        orderBy.set(orderBy.get() + 1);

        dataList.add(data);
    }

    private static int setInOrOut(TestDataPojo data, int cursor, List<String> lines, String specifyTag) {
        // 跳commend
        cursor = skipCommend(cursor, lines);
        if (cursor < lines.size()) {
            String line = lines.get(cursor).trim();
            String tag = checkLineHeader(line);
            if (specifyTag.equals(tag)) {
                cursor = correctBrackets(cursor, lines, data, specifyTag);
            }
        }
        return cursor;
    }

    private static int correctBrackets(int cursor, List<String> lines, TestDataPojo data, String specifyTag) {

        String line = lines.get(cursor).trim();
        StringBuilder trueBracketStr = new StringBuilder(line);
        Stack<String> bracket = new Stack<>();
        bracket.push("#");

        cursor++;
        if (chkBracketSpecification2(line, bracket)) {
            setTestData(data, specifyTag, trueBracketStr);
        } else {
            // 跳commend
            while ((cursor = skipCommend(cursor, lines)) < lines.size()) {
                line = lines.get(cursor).trim();
                trueBracketStr.append(line);
                cursor++;
                if(chkBracketSpecification2(line, bracket)) {
                    setTestData(data, specifyTag, trueBracketStr);
                    break;
                }
            }
        }

        return cursor;
    }

    private static void setTestData(TestDataPojo data, String specifyTag, StringBuilder trueBracketStr) {
        if (TCt.tagIn.equals(specifyTag)) {
            data.setInputString(trueBracketStr.toString());
        } else {
            data.setAnswer(trueBracketStr.toString());
        }
    }

    private static int skipCommend(int cursor, List<String> lines) {
        while (cursor < lines.size()) {
            String tag = checkLineHeader(lines.get(cursor).trim());
            switch (tag) {
                case TCt.tagStartCms:
                    cursor = skipStarCommend(cursor, lines);
                    continue;
                case TCt.tagSkip:
                    cursor++;
                    continue;
            }
            break;
        }

        return cursor;
    }

    private static int skipStarCommend(int cursor, List<String> lines) {
        while (cursor < lines.size()) {
            if (TCt.tagEndCms.equals(checkLineEnd(lines.get(cursor).trim()))) break;
            cursor++;
        }
        return cursor;
    }

    private static boolean chkBracketSpecification2(String line, Stack<String> bracket) {
        String temp = line.replaceAll("[^{}]", "");

        for (int i = 0; i < temp.length() ; i++) {
            if (temp.charAt(i) == '{') {
                bracket.push("{");
            } else if (temp.charAt(i) == '}' && bracket.peek().equals("{")) {
                bracket.pop();
            }
        }

        return bracket.peek().equals("#");
    }

    private static String checkLineHeader(String line) {
        String tag = "";
        if (line.isEmpty() || line.startsWith("//")) {
            tag = TCt.tagSkip;
        }
        else if (line.startsWith("TestCaseName:") || line.startsWith("TestCaseIndex:")) {
            tag = TCt.tagTitle;
        }
        else if (line.startsWith("Input:") || line.startsWith("input:")) {
            tag = TCt.tagIn;
        }
        else if (line.startsWith("Output:") || line.startsWith("output:")) {
            tag = TCt.tagOut;
        }
        else if (line.startsWith("/*")) {
            tag = TCt.tagStartCms;
        }
        return tag;
    }

    private static String checkLineEnd(String line) {
        String tag = "";
        if (line.endsWith("*/")) {
            tag = TCt.tagEndCms;
        }
        return tag;
    }

}
